package com.jinxin.platform.cdacscontrolmgr.websocket;

import com.alibaba.fastjson.JSONObject;
import com.jinxin.platform.cdacscontrolmgr.bean.CdparkmanagerProject;
import com.jinxin.platform.cdacscontrolmgr.bean.CdyardmgrEvent;
import com.jinxin.platform.cdacscontrolmgr.bean.CdyardmgrPushInfo;
import com.jinxin.platform.cdacscontrolmgr.bean.bo.OptionItem;
import com.jinxin.platform.cdacscontrolmgr.bean.enums.ProjectType;
import com.jinxin.platform.cdacscontrolmgr.common.Constant;
import com.jinxin.platform.cdacscontrolmgr.common.SysOrgInfo;
import com.jinxin.platform.cdacscontrolmgr.rpc.CdacscontrolmgrRpc;
import com.jinxin.platform.cdacscontrolmgr.service.ICdacscontrolmgrProjectService;
import com.jinxin.platform.cdacscontrolmgr.service.impl.CdacscontrolmgrProjectServiceImpl;
import com.jinxin.platform.cdacscontrolmgr.utils.DateUtil;
import com.jinxin.platform.cdacscontrolmgr.utils.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * All rights Reserved, Designed By www.beonelot.com
 *
 * @version: V1.0
 * @Copyright: www.beonelot.com Inc. All rights reserved.
 * @Description：
 * @Date: 2021-11-30
 * @Author: Lingnan
 **/
// 不能通过@Autowired等注入bean
@ServerEndpoint("/cdacscontrolmgr/websocket/{userId}")
@Component
@Slf4j
public class CdacscontrolmgrWebSocket {
    /**
     * 存放所有在线的客户端
     */
    public static final Map<String, Session> clients = new ConcurrentHashMap<>();
    /**
     * 连接建立成功调用的方法
     *
     * @param session 可选的参数。session为与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(@PathParam("userId") String userId, Session session) {
        /*
         * 存放所有在线的客户端
         */
        log.info("[门禁项目管理]有新连接加入：{}", userId);
        clients.put(userId, session);
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(@PathParam("userId") String userId, Session session) {
        clients.remove(userId);
        log.info("onClose,{}", userId);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param userId 用户ID
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(@PathParam("userId") String userId, String message) {
        log.info("{}发送信息,内容为{}", userId, message);
        try{
            JSONObject jsonObject = JSONObject.parseObject(message);
            Integer pullMsgFlag = jsonObject.getInteger("pullMsg");
            CdacscontrolmgrRpc cdacscontrolmgrRpc = (CdacscontrolmgrRpc) SpringContextUtils.getBeanByClass(CdacscontrolmgrRpc.class);
            if(pullMsgFlag != null){ //主动获取消息
                sendMsgToUser(userId,cdacscontrolmgrRpc);
                return;
            }
            //String id = jsonObject.getString("id");
            String projectId = jsonObject.getString("projectId");
            Integer status = jsonObject.getInteger("status");//1呼叫中，2已接听，3已取消
            String msgId = jsonObject.getString("msgId");
            if(StringUtils.isEmpty(userId) || status == null){return;}
            if(!StringUtils.isEmpty(msgId)){
                CdyardmgrPushInfo pushInfo = new CdyardmgrPushInfo();
                pushInfo.setId(msgId);
                pushInfo.setStatus(Constant.MSG_STATUS_READ);
                cdacscontrolmgrRpc.saveOrUpdate(pushInfo);
                sendMsgToUser(userId,cdacscontrolmgrRpc);
                return;
            }
            JSONObject jsonObj = new JSONObject();
            jsonObj.put("status",status);
            jsonObj.put("userId",userId);
            CdparkmanagerProject projectInfo = cdacscontrolmgrRpc.getProjectInfoById(projectId);
            if(projectInfo == null){
                log.info("语音呼叫查询项目不存在");
                return;
            }
            jsonObj.put("projectInfo",projectInfo);
            List<String> userList = getUserList(cdacscontrolmgrRpc,projectId,userId);
            if(userList.size() == 0){return;}
            sendMessageToOtherUsers(jsonObj,userId,cdacscontrolmgrRpc,projectId,projectInfo,userList);
            if(!StringUtils.isEmpty(msgId)){
                return;
            }
            List<String> offlineUserList = new ArrayList<>();//未登录用户列表通过用户模块发送消息
            userList.forEach(uId->{
                if(!clients.containsKey(uId)){
                    offlineUserList.add(uId);
                }
            });
            String msg = getMsgByStatus(status);
            String title = "语音呼叫消息提醒";
            String source = "云坐席";
            for(String uId : offlineUserList){
                String time = DateUtil.getDateTimeAsString(LocalDateTime.now(),"");
                cdacscontrolmgrRpc.sendMessage(uId,"",msg,time,title,source);
            }

        }catch(Exception e){
            e.printStackTrace();
            log.error("handleMessage error: " + e.toString());
        }
    }

    private void sendMsgToUser(String userId,CdacscontrolmgrRpc cdyardmgrRpc){
        List<CdyardmgrEvent> infos = cdyardmgrRpc.listEventByUserId(userId);
        List<CdyardmgrEvent> infos1 = infos.stream().filter(
                info->Constant.MSG_STATUS_READ.equals(info.getStatus())).collect(Collectors.toList());
        List<CdyardmgrEvent> infos2 = infos.stream().filter(
                info->Constant.MSG_STATUS_UNREAD.equals(info.getStatus())).collect(Collectors.toList());
        JSONObject msgObj = new JSONObject();
        msgObj.put("readMsgLit",infos1);
        msgObj.put("unreadMsgLit",infos2);
        msgObj.put("purpose","event");//事件的消息
        Session session = clients.get(userId);
        if (session != null && session.isOpen()) {
            synchronized (session){
                session.getAsyncRemote().sendText(msgObj.toJSONString());
            }
        }
    }
    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(@PathParam("userId") String userId, Session session, Throwable error) {
        log.error("发生错误,{}", userId);
        error.printStackTrace();
    }

    /**
     * 群发消息
     *
     * @param message 消息内容
     */
    public void sendMessage(String message) {
        for (Map.Entry<String, Session> sessionEntry : clients.entrySet()) {
            Session toSession = sessionEntry.getValue();
            log.info("服务端给客户端[{}]发送消息{},", sessionEntry.getKey(), message);
            if (toSession != null && toSession.isOpen()) {
                synchronized (toSession){
                    toSession.getAsyncRemote().sendText(message);
                }
            }
        }
    }

    public void sendMessageToUser(String userId, String message) {
        Session toSession = clients.get(userId);
        log.info("sendMessageToUser[{}]发送消息{},", userId, message);
        if(toSession == null){return;}
        synchronized (toSession){
            toSession.getAsyncRemote().sendText(message);
        }
    }

    public boolean sendMessageToOtherUsers(JSONObject message,String otherId,CdacscontrolmgrRpc cdyardmgrRpc,
                                           String projectId,CdparkmanagerProject projectInfo,List<String> userList) {
        int managerFlag = Constant.MANAGER_FLAG_YES.equals(projectInfo.getManagerFlag())
                ? Constant.MANAGER_FLAG_YES : Constant.MANAGER_FLAG_NO;
        String projectName = projectInfo.getProjectName();
        int projectType = projectInfo.getProjectType();
        String ssfws = projectInfo.getOrganName();
        String orgId = projectInfo.getOrganId();
        boolean allSendSuccess = true;
        Set<String> clientIds = clients.keySet();
        Session session = null;
        for (String clientId : clientIds) {
            if(clientId.equals(otherId) || !userList.contains(clientId)){continue;}
            // 新增一条消息(事件)
            CdyardmgrEvent event = new CdyardmgrEvent();
            event.setDid(otherId);
            event.setCreateTime(LocalDateTime.now());
            event.setManagerFlag(managerFlag);
            event.setUserId(clientId);
            event.setStatus(Constant.MSG_STATUS_UNREAD);
            event.setProject(projectName);
            event.setProjectId(projectId);
            event.setType(Constant.MSG_TYPE_VOICE);
            event.setProjectType(ProjectType.getDesc(projectType));
            event.setOrgId(orgId);
            String eventName = cdyardmgrRpc.queryBarrierByVideoId(otherId);
            event.setEvent(eventName+"语音呼叫");
            event.setSsfws(ssfws);
            cdyardmgrRpc.saveOrUpdateEvent(event);
            List<CdyardmgrEvent> infos = cdyardmgrRpc.listEventByUserId(clientId);
            List<CdyardmgrEvent> infos1 = infos.stream().filter(
                    info->Constant.MSG_STATUS_READ.equals(info.getStatus())).collect(Collectors.toList());
            List<CdyardmgrEvent> infos2 = infos.stream().filter(
                    info->Constant.MSG_STATUS_UNREAD.equals(info.getStatus())).collect(Collectors.toList());
            message.put("readMsgLit",infos1);
            message.put("unreadMsgLit",infos2);
            message.put("purpose","event");//事件的消息
            session = clients.get(clientId);
            if (session !=null && session.isOpen()) {
                synchronized (session){
                    session.getAsyncRemote().sendText(message.toJSONString());
                }
            }
        }
        return allSendSuccess;
    }

    private List<String> getUserList(CdacscontrolmgrRpc cdacscontrolmgrRpc, String projectId,String uId){
        ICdacscontrolmgrProjectService cdacscontrolmgrProjectService =
                (ICdacscontrolmgrProjectService) SpringContextUtils.getBeanByClass(CdacscontrolmgrProjectServiceImpl.class);
        List<String> userList = new ArrayList<>();
        CdparkmanagerProject project = cdacscontrolmgrProjectService.selectByKey(projectId);
        if(project == null){return userList;}
        if(project.getManagerFlag() == 1){ // 代管中的发送消息给创建者(财门)的组织id下的人员
            SysOrgInfo orgInfo = cdacscontrolmgrRpc.getOrgByUserId(project.getUserId());
            if(orgInfo == null){return userList;}
            List<OptionItem> userVOList = cdacscontrolmgrRpc.getUsersByOrgId(orgInfo.getOrgId());
            userVOList.forEach(user->{
                String userId = user.getId();
                if(!userId.equals(uId)){
                    userList.add(userId);
                }
            });
        }else if(project.getManagerFlag() == 2){ //未代管的发送给服务商
            List<OptionItem> userVOList = cdacscontrolmgrRpc.getUsersByOrgId(project.getOrganId());
            userVOList.forEach(user->{
                String userId = user.getId();
                if(!userId.equals(uId)){
                    userList.add(userId);
                }
            });
        }
        return userList;
    }

    private String getMsgByStatus(Integer status){
        if(status == null){return "";}
        switch (status){
            case 1:return "语音呼叫中";
            case 2:return "语音呼叫已接听";
            case 3:return "语音呼叫已取消";
            default:return "";
        }
    }
}
